package com.denghq.projectbuilder.component.consul.config.configuration;

import com.denghq.projectbuilder.common.util.BeanTool;
import com.denghq.projectbuilder.component.config.domain.ConfigAutoRegister;
import com.denghq.projectbuilder.component.config.metadata.ConfigDescriptor;
import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.QueryParams;
import com.ecwid.consul.v1.Response;
import com.ecwid.consul.v1.kv.model.GetValue;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;

@Slf4j
public class ConsulConfigAutoRegister extends ConfigAutoRegister {


    private final ConsulClient consul;

    //consul的key分割符，同一级目录下面的可以批量获取
    private final static String KEY_SEPARATOR = "/";

    private final ConsulConfigProperties properties;


    @Getter
    private final LinkedHashMap<String, Long> consulIndexes;

    public ConsulConfigAutoRegister(ConsulClient consul, List<ConfigDescriptor> configDescriptorList, ConsulConfigProperties configProperties, String appNo) {
        super(configDescriptorList, appNo);
        this.properties = configProperties;
        this.consul = consul;
        this.consulIndexes = Maps.newLinkedHashMap();
    }


    @Override
    protected List<ConfigDescriptor> getConfigsFromRemote(List<ConfigDescriptor> currentConfigs) {
        List<ConfigDescriptor> configDescriptors = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(currentConfigs)) {
            List<GetValue> values = this.getValueFromConsul(currentConfigs, consulIndexes);
            if (!CollectionUtils.isEmpty(values)) {
                currentConfigs.forEach(e -> {
                    String categoryNo = e.getCategoryNo();
                    for (int i = 0, len = values.size(); i < len; i++) {
                        GetValue getValue = values.get(i);
                        if (getValue.getKey().equals(categoryNo)) {
                            String value = getValue.getDecodedValue();
                            Optional.ofNullable(BeanTool.jsonStrToObject(value, ConfigDescriptor.class)).ifPresent(configDescriptors::add);
                            break;
                        }
                    }
                });
            }
        }
        return configDescriptors;
    }

    @Override
    protected void writeConfigToRemote(List<ConfigDescriptor> configs) {
        if (!CollectionUtils.isEmpty(configs)) {
            configs.forEach(c -> {
                boolean res = writeConfigToConsul(c);
                if (!res) {
                    log.warn("写入配置到consul报错，配置信息：{}", c);
                }
            });
        }
    }

    /**
     * 写配置到配置中心
     *
     * @param config
     * @return
     */
    public boolean writeConfigToConsul(ConfigDescriptor config) {
        Assert.notNull(config, "配置类不能为空！");
        Assert.isTrue(config.isAutoRegiste(), "只能注册属于本服务的配置，appNo非法:" + config.getAppNo());
        Response<Boolean> response = this.consul.setKVValue(config.getCategoryNo(), BeanTool.objectToJsonStr(config));
        return response.getValue();
    }


    /**
     * 2.获取老的配置类描述信息
     *
     * @return
     */
    public List<GetValue> getValueFromConsul(List<ConfigDescriptor> configDescriptor, LinkedHashMap<String, Long> _consulIndexes) {

        List<GetValue> values = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(configDescriptor)) {
            //Set<String> categoryNoSet = Sets.newHashSet();
            Set<String> consulKeySet = Sets.newHashSet();
            configDescriptor.forEach(e -> {
                String categoryNo = e.getCategoryNo();
                if (StringUtils.isNotBlank(categoryNo)) {
                    consulKeySet.add(categoryNo.split(KEY_SEPARATOR)[0]);
                    // categoryNoSet.add(categoryNo);
                }
            });

            if (!CollectionUtils.isEmpty(consulKeySet)) {
                String aclToken = this.properties.getAclToken();
                if (StringUtils.isEmpty(aclToken)) {
                    aclToken = null;
                }

                Iterator var1 = consulKeySet.iterator();
                while (var1.hasNext()) {
                    String context = (String) var1.next();
                    Long currentIndex = -1L;
                    if (!CollectionUtils.isEmpty(_consulIndexes)) {
                        currentIndex = _consulIndexes.get(context) == null ? -1L : _consulIndexes.get(context);
                    }

                    Response<List<GetValue>> response = this.consul.getKVValues(context, aclToken, new QueryParams((long) this.properties.getWatch().getWaitTime(), currentIndex));

                    if (!CollectionUtils.isEmpty(response.getValue())) {
                        Long newIndex = response.getConsulIndex();
                        _consulIndexes.put(context, newIndex);
                        List<GetValue> valueList = response.getValue();
                        if (!CollectionUtils.isEmpty(valueList)) {
                            values.addAll(valueList);
                        }
                    } else if (log.isTraceEnabled()) {
                        log.trace("No value for context " + context);
                    }

                }

            }
        }
        return values;

    }

}
